    import yaml
    import pandas as pd
    import numpy as np
    import re
    import plotly.graph_objects as go
    import plotly.io as pio
    import pandas as pd
    import numpy as np
    import plotly.offline as pyo

    def parse_time_info(line):
        # 正则表达式模式,匹配2024-09-01 12:00:00.000
        pattern = r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}"
        time_info = ''

        match = re.search(pattern, line)

        if match:
            time_info = match.group()
        else:
            print("未找到时间信息")

        return time_info


    def load_xlsx_config(xlsx_file):
        df = pd.read_excel(xlsx_file, usecols='A:E')
        df = df.rename(columns={'功能': 'func', '子功能': 'subfunc','开始日志': 'startlog', '结束日志': 'endlog','是否在图表中体现': 'shown'})
        df['func'] = df['func'].ffill()
        df['shown'] = df['shown'].fillna('否')
        return df


    def load_yaml_config(yaml_file):
        with open(yaml_file, 'r', encoding='utf-8') as file:
            data = yaml.safe_load(file)

        records = []

        for func_name, func_details in data['功能'].items():
            # Add the main function record
            main_record = {
                '功能': func_name,
                '子功能': '',
                '开始日志': func_details.get('开始日志', ''),
                '结束日志': func_details.get('结束日志', ''),
                '是否在图表中体现': func_details.get('是否在图表中体现', '')
            }
            records.append(main_record)

            # Add sub-function records
            if '子功能' in func_details:
                for sub_func_name, sub_func_details in func_details['子功能'].items():
                    sub_record = {
                        '功能': func_name,
                        '子功能': sub_func_name,
                        '开始日志': sub_func_details.get('开始日志', ''),
                        '结束日志': sub_func_details.get('结束日志', ''),
                        '是否在图表中体现': sub_func_details.get('是否在图表中体现', '')
                    }
                    records.append(sub_record)

        # Create DataFrame
        df = pd.DataFrame(records)

        df = df.rename(columns={'功能': 'func', '子功能': 'subfunc','开始日志': 'startlog', '结束日志': 'endlog','是否在图表中体现': 'shown'})
        df['func'] = df['func'].ffill()
        df['shown'] = df['shown'].fillna('否')
        return df


    def parse_log_config(cfg_df, log_file):

        with open(log_file, 'r') as file:
            for line in file:
                for row in cfg_df.itertuples():
                    index = row.Index
                    if row.startlog in line:
                        t = parse_time_info(line)
                        cfg_df.at[index, 'starttime'] =  pd.to_datetime(t)
                    elif row.endlog in line:
                        t = parse_time_info(line)
                        cfg_df.at[index, 'endtime'] =  pd.to_datetime(t)


        return cfg_df

    # 自定义格式化时间差
    def format_timedelta(td):
        total_seconds = int(td.total_seconds())
        milliseconds = int(td.microseconds / 1000)
        hours, remainder = divmod(total_seconds, 3600)
        minutes, seconds = divmod(remainder, 60)
        return f"{hours:02}:{minutes:02}:{seconds:02}.{milliseconds:03}"


    def gen_html_report(df_tasks):
        
        # 找到最小的开始时间
        min_start_time = df_tasks['Start'].min()

        # 计算相对时间
        df_tasks['Start_relative'] = (df_tasks['Start'] - min_start_time).dt.total_seconds()
        df_tasks['Finish_relative'] = (df_tasks['Finish'] - min_start_time).dt.total_seconds()
        
        
        df_tasks['Start_r'] = (df_tasks['Start'] - min_start_time).apply(format_timedelta)
        df_tasks['Finish_r'] = (df_tasks['Finish'] - min_start_time).apply(format_timedelta)
        

        df_tasks['elapsed'] = df_tasks['Finish'] - df_tasks['Start']
        df_tasks['elapsed'] = df_tasks['elapsed'].apply(format_timedelta)

        # 创建图表
        fig = go.Figure()
        
        # 记录所有任务和子任务以显示在 y 轴上的顺序
        y_order = []

        tick_texts = []

        # 添加每个任务的数据
        for index, row in df_tasks.iterrows():

            # if row['shown'] == '否':
            #     continue
            
            # 添加任务到 y 轴顺序
            task_label = f"{row['Task']}"
            y_order.append(task_label)
            
            # 创建 hover text
            hover_text = f"任务: {row['Task']}<br>开始: {row['Start_r']}<br>结束: {row['Finish_r']}"
            # 创建标签文本
            # tick_text = f"{row['Task']} ({row['Start'].strftime('%H:%M:%S')} - {row['Finish'].strftime('%H:%M:%S')})"
            tick_text = f"{row['Task']} ({row['elapsed']})"
            tick_texts.append(tick_text)
            
            # 添加任务条
            fig.add_trace(go.Scatter(
                x=[row['Start_relative'], row['Finish_relative']],
                y=[task_label, task_label],
                mode='lines',
                line=dict(color=row['Color'], width=20),  # 设置任务条的颜色
                name=row['Task'],
                showlegend=False,
                hoverinfo='text',  # 显示自定义悬停信息
            
                text=hover_text
            ))


            # # 添加永久显示的注释
            # fig.add_annotation(
            #     x=row['Finish_relative'] + 20,
            #     y=task_label,
            #     text=hover_text,
            #     showarrow=False,
            #     yshift=10  # 调整位置       
            # )               

        # 设置 x 轴刻度格式
        def format_time(x):
            return (min_start_time + pd.to_timedelta(x, unit='s')).strftime('%H:%M:%S')
        
        # 设置布局
        fig.update_layout(
            # title="XXX性能报告",
            # xaxis_title="时间",
            # yaxis_title="任务",
            height=len(y_order) * 30,
            # width=1500,
            showlegend=False,
            # plot_bgcolor='lightyellow',  # 设置图表区域的背景颜色
            # paper_bgcolor='lightblue',    # 设置整个图表的背景颜色
            dragmode=False,
            yaxis=dict(
                # autorange="reversed",
                tickvals=y_order,
                ticktext=tick_texts,
                autorange=False,  # 禁用自动范围
                range=[-1, len(y_order)],  # 增加顶部和底部的空间
                gridcolor='lightgrey'  # 设置x轴背景格子颜色
            ),
            xaxis=dict(
                gridcolor='#FFDDC1'  # 设置y轴背景格子颜色
            )
        )
        
        # 更新悬停提示信息的背景颜色
        fig.update_traces(hoverlabel=dict(bgcolor="lightblue"))

        # 更新布局的边距
        fig.update_layout(margin=dict(l=50, r=50, t=20, b=20))

        # # 更新 x 轴刻度
        # fig.update_xaxes(
        #     tickmode='array',
        #     tickvals=np.arange(0, df_tasks['Finish_relative'].max() + 60, 60),  # 设置刻度间隔为60s
        #     ticktext=[format_time(x) for x in np.arange(0, df_tasks['Finish_relative'].max() + 60, 60)]  # 设置刻度文本
        # )

        # 更新 x 轴刻度
        fig.update_xaxes(
            tickmode='array',
            tickvals=np.arange(0, df_tasks['Finish_relative'].max() + 60, 60),  # 设置刻度间隔为60s
            ticktext=[(pd.to_datetime("00:00:00") + pd.to_timedelta(x, unit='s')).strftime('%H:%M:%S') 
                    for x in np.arange(0, df_tasks['Finish_relative'].max() + 60, 60)]  # 从00:00:00开始计时
        )


        # 配置移除工具栏按钮
        config = {
            'doubleClick': 'reset', # 禁用双击缩放
            'modeBarButtonsToRemove': ['zoom', 'pan', 'select', 'zoomIn', 'zoomOut', 'autoScale', 'resetScale'],
            'displaylogo': False  # 如果想要移除Plotly的logo
        }


        # 显示图表
        fig.show(config=config)
        # 将图保存为HTML文件
        pyo.plot(fig, filename='your_plot.html', config=config, auto_open=False)

        html_str = pyo.plot(fig,output_type='div',  config=config)



        # 自定义样式
        styles = [
            dict(selector='table', props=[('border-collapse', 'collapse'), ('width', '100%'), ('border-spacing', '0'), ('margin', '0')]),
            dict(selector='th, td', props=[('border', '1px solid black'), ('padding', '0'), ('text-align', 'left'), ('margin', '0')]),
            dict(selector='th', props=[('background-color', '#f2f2f2')])
        ]

        df_html = df_tasks[['Task','Start','Finish','elapsed']]
        df_html = df_html.rename(columns={'Task': '功能名称', 'Start':'开始时间', 'Finish':'结束时间', 'elapsed':'总共耗时'})

        # 转换为 datetime 对象，并格式化为毫秒显示3位
        df_html['开始时间'] = pd.to_datetime(df_html['开始时间']).dt.strftime('%Y-%m-%d %H:%M:%S.%f').str[:-3]
        df_html['结束时间'] = pd.to_datetime(df_html['结束时间']).dt.strftime('%Y-%m-%d %H:%M:%S.%f').str[:-3]
        print(df_html)
        # 转换为 HTML 并应用样式
        html = df_html.style.set_table_styles(styles).hide(axis='index') .to_html()
        # 使用正则表达式去掉ID信息
        html = re.sub(r'#T_[a-zA-Z0-9_]+', '', html)
        myhtml = f'''
        <html>
        <head>  
            <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
            <title>XXX报告</title>
            <script>
                document.addEventListener('wheel', function(event) {{
                    if (event.ctrlKey) {{
                        event.preventDefault();
                    }}
                }}, {{ passive: false }});
            </script>
        </head>
        <body>
        <div>XXX报告</div>
        {html_str}
        <br>
        {html}
        </body>
        </html>
        '''

        with open('demo.html', 'w', encoding='utf-8') as file:
            file.write(myhtml)


    df = load_yaml_config('config.yaml')
    df = parse_log_config(df,'trace.log')


    df['Task'] = df.apply(lambda row: row['func'] if pd.isna(row['subfunc']) or len(row['subfunc']) == 0 else f"{row['func']}[{row['subfunc']}]", axis=1)


    df['Color'] = df.apply(lambda row: 'blue' if pd.isna(row['subfunc']) or len(row['subfunc']) == 0 else '#CCCCCC', axis=1)

    df = df.rename(columns={'starttime': 'Start', 'endtime': 'Finish'})

    # df['Color'] = np.where(df['subfunc'].isna(), '#CCCCCC', 'blue')

    df = df[['Task', 'Start', 'Finish', 'Color']]


    df_reversed = df.iloc[::-1].reset_index(drop=True)
    gen_html_report(df_reversed)


    # df = load_xlsx_config('config.xlsx')
    # df = parse_log_config(df,'trace.log')
    # df = df[['func', 'starttime', 'endtime']]
    # print(df)